001    /*
002     * Copyright 2005 Stephen J. McConnell
003     *
004     * Licensed  under the  Apache License,  Version 2.0  (the "License");
005     * you may not use  this file  except in  compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *   http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed  under the  License is distributed on an "AS IS" BASIS,
012     * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
013     * implied.
014     *
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package net.dpml.library.impl;
020    
021    import java.util.ArrayList;
022    import java.util.Enumeration;
023    import java.util.Properties;
024    
025    import net.dpml.library.Dictionary;
026    import net.dpml.library.info.AbstractDirective;
027    
028    import net.dpml.util.PropertyResolver;
029    
030    /**
031     * Utility class used for construction of a module model from an XML source.
032     *
033     * @author <a href="http://www.dpml.net">The Digital Product Meta Library</a>
034     * @version 1.0.0
035     */
036    public class DefaultDictionary implements Dictionary
037    {
038        private final DefaultDictionary m_parent;
039        private final AbstractDirective m_directive;
040        private final Properties m_properties;
041        
042       /**
043        * Creation of a new dictionary.  The dictionary provides support
044        * for property inheritance within the hierachy of of modules based
045        * an a single root virtual module.  When handling a propety request
046        * the dictionary will attempt to resolve the property value using 
047        * local property values.  If the value is unresolved, the implemenetation
048        * will attempt to delegate the request to a parent dictionary if available.
049        *
050        * @param parent the parent dictionary (possibly null)
051        * @param directive an abstract directive containing local properties
052        */
053        public DefaultDictionary( DefaultDictionary parent, AbstractDirective directive )
054        {
055            if( null == directive )
056            {
057                throw new NullPointerException( "directive" );
058            }
059            m_parent = parent;
060            m_directive = directive;
061            
062            Properties properties = getParentProperties();
063            m_properties = new Properties( properties );
064            Properties local = directive.getProperties();
065            String[] keys = getLocalPropertyNames( local );
066            for( int i=0; i<keys.length; i++ )
067            {
068                String key = keys[i];
069                String value = local.getProperty( key );
070                m_properties.setProperty( key, value );
071            }
072        }
073        
074        //----------------------------------------------------------------------------
075        // Dictionary
076        //----------------------------------------------------------------------------
077        
078       /**
079        * Return the property names associated with the dictionary.
080        * @return the array of property names
081        */
082        public String[] getPropertyNames()
083        {
084            return getLocalPropertyNames( m_properties );
085        }
086        
087       /**
088        * Return the local property names associated with the dictionary.
089        * @return the array of local property names
090        */
091        public String[] getLocalPropertyNames()
092        {
093            return getLocalPropertyNames( m_directive.getProperties() );
094        }
095        
096       /**
097        * Return a property value.
098        * @param key the property key
099        * @return the property value
100        */
101        public String getProperty( String key )
102        {
103            return getProperty( key, null );
104        }
105        
106       /**
107        * Return a property value.
108        * @param key the property key
109        * @param value the default value
110        * @return the property value
111        */
112        public String getProperty( String key, String value )
113        {
114            String result = m_properties.getProperty( key, value );
115            return resolve( result );
116        }
117        
118       /**
119        * Return an integer property value.
120        * @param key the property key
121        * @param value the default value
122        * @return the property value as an integer
123        * @exception NumberFormatException if underlying property value 
124        *    cannot be resolved to an integer
125        */
126        public int getIntegerProperty( String key, int value )
127        {
128            String result = m_properties.getProperty( key );
129            if( null == result )
130            {
131                return value;
132            }
133            else
134            {
135                String literal = resolve( result );
136                return Integer.parseInt( literal );
137            }
138        }
139        
140       /**
141        * Return an boolean property value.
142        * @param key the property key
143        * @param value the default value
144        * @return the property value as an boolean
145        * @exception NumberFormatException if underlying property value 
146        *    cannot be resolved to an integer
147        */
148        public boolean getBooleanProperty( String key, boolean value )
149        {
150            String result = m_properties.getProperty( key );
151            if( null != result )
152            {
153                return Boolean.valueOf( result ).booleanValue();
154            }
155            else
156            {
157                return value;
158            }
159        }
160       /**
161        * Evaluate and expand any symbolic references in the supplied value.
162        * @param value the value to resolve
163        * @return the resolved value
164        */
165        public String resolve( String value )
166        {
167            return PropertyResolver.resolve( m_properties, value );
168        }
169        
170        //----------------------------------------------------------------------------
171        // internal
172        //----------------------------------------------------------------------------
173        
174        void setProperty( String name, String value )
175        {
176            m_properties.setProperty( name, value );
177        }
178        
179        AbstractDirective getAbstractDirective()
180        {
181            return m_directive;
182        }
183        
184        Properties getProperties()
185        {
186            return m_properties;
187        }
188        
189        private Properties getParentProperties()
190        {
191            if( null == m_parent )
192            {
193                return new Properties();
194            }
195            else
196            {
197                return m_parent.getProperties();
198            }
199        }
200        
201        private String[] getLocalPropertyNames( Properties properties )
202        {
203            ArrayList list = new ArrayList();
204            Enumeration names = properties.propertyNames();
205            while( names.hasMoreElements() )
206            {
207                list.add( (String) names.nextElement() );
208            }
209            return (String[]) list.toArray( new String[0] );
210        }
211    
212        Properties getExportProperties()
213        {
214            String[] keys = getLocalPropertyNames();
215            Properties properties = new Properties();
216            for( int i=0; i<keys.length; i++ )
217            {
218                String key = keys[i];
219                String value = getProperty( key );
220                properties.setProperty( key, value );
221            }
222            return properties;
223        }
224    }